package com.lot.ws.simulator;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Random;
import java.util.concurrent.CountDownLatch;

import com.lot.ws.dto.ReadingDetails;
import com.lot.ws.dto.ReadingRequest;
import com.lot.ws.resource.MSRResource;
import com.lot.ws.util.DateUtil;

public class DataGenerator implements Runnable {

	private final ReadingDetails source;

	static final String deviceIds[] = { "e01", "e02", "e03", "e04", "e05",
			"e06", "deg000", "e0000", "f01" , "hrm00", 
	//more temp devices		
	"deg1", "deg1", "deg3"};
	static final String deviceTypes[] = { "lights", "cooling", "kitchen-appliances",
			"refrigerator", "heating", "entertainment", "temperature",
			"totalec", "door" , "heart-rate-mtr"};

	Random vvlowRand = new Random();
	String vvlow = getRandomValue(vvlowRand, 0, 10, 2);
	Random vlowRand = new Random();
	String vlow = getRandomValue(vlowRand, 10, 100, 2);
	Random lowRand = new Random();
	String low = getRandomValue(lowRand, 100, 400, 2);
	Random mediumRand = new Random();
	String medium = getRandomValue(mediumRand, 400, 1000, 2);
	Random highRand = new Random();
	String high = getRandomValue(highRand, 1000, 1500, 2);
	Random vhighRand = new Random();
	String vhigh = getRandomValue(vhighRand, 1500, 3000, 2);
	
	Random tempMiamiRandDay = new Random();
	String tempMiamiDay = getRandomValue(tempMiamiRandDay, 25,32, 2);
	Random tempMiamiRandNight = new Random();
	String tempMiamiNight = getRandomValue(tempMiamiRandNight, 20, 25, 2);

	Random tempLonRandDay = new Random();
	String tempLonDay = getRandomValue(tempLonRandDay, 17, 23, 2);
	Random tempLonRandNight = new Random();
	String tempLonNight = getRandomValue(tempLonRandNight, 11, 17, 2);
	
	Random freqRand = new Random(); 
	Integer freq = freqRand.nextInt(10) + 1;

	//resting heart rate 40-100
	Random heartRateRandNormal = new Random(); 
	String heartRateNormal =  getRandomValue(heartRateRandNormal, 60, 100, 0);
	
	Random heartRateRandLow = new Random(); 
	String heartRateLow =  getRandomValue(heartRateRandLow, 0, 50, 0);
	Random heartRateRandHigh = new Random(); 
	String heartRateHigh =  getRandomValue(heartRateRandHigh, 101, 350, 0);
	
	Random countRan = new Random(); 
	int countRand = countRan.nextInt(14) + 1;
	
	int abnormalhr[] = {-1,0,1,0,1,0,1,0,1,-1,0,1,0,0,-1};
	int normalhr[] = {0,0,-1,0,0,0,0,0,0,1,0,0,0,0,0};
	
	
	DecimalFormat df = new DecimalFormat("#.00");

	private final CountDownLatch countDownLatch;
	private final Date recordDate;
	
	public DataGenerator(ReadingDetails readingDetails, Date curr,
			CountDownLatch latch) {
		super();
		this.source = readingDetails;
		this.countDownLatch = latch;
		this.recordDate = curr;
	}

	public void run() {
		try {

			Date now1 = new Date();

			List<ReadingDetails> l = new ArrayList<ReadingDetails>();

			Date now = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss",
					Locale.ENGLISH).parse(DateUtil.convertDateFormat(now1,
					"dd/MM/yyyy HH:mm:ss"));
			String dateStr = String.valueOf(now.getTime());
			dateStr = DateUtil.makeFixedLength(dateStr);
			source.setRecordTime(now.toString());
			
			//Actual Simulator
//			String recordTime = DateUtil.convertDateFormat(now1,
//					"dd/MM/yyyy HH:mm:ss");
			String recordTime = DateUtil.convertDateFormat(recordDate,"dd/MM/yyyy HH:mm:ss");
					
//			System.out.println(recordTime+ " ..... "+source.getSrcId());

			//Home: location Miami- coastal warm, low enter
			if (source.getSrcId().equals(DataSimulator.srcs[0].getSrcId())) {
				
				//lights
				ReadingDetails srcdevice11 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[0], deviceIds[0],
						source.getLocation(), recordTime, low.toString());

				
				//kitchen-appliances
				ReadingDetails srcdevice13 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[2], deviceIds[2],
						source.getLocation(), recordTime, high.toString());

				//refrigerator
				ReadingDetails srcdevice14 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[3], deviceIds[3],
						source.getLocation(), recordTime, high.toString());

				//entertainment
				ReadingDetails srcdevice16 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[5], deviceIds[5],
						source.getLocation(), recordTime, low.toString());

				//temperature
				ReadingDetails srcdevice17 = null;
				if (isDay(now)) {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempMiamiDay);
				} else {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempMiamiNight);
				}

				//as temperature increases cooling increases
				//cooling
				ReadingDetails srcdevice12 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[1], deviceIds[1],
						source.getLocation(), recordTime, df.format((Double.parseDouble(srcdevice17.getValue()) * 25d) + Double.parseDouble(vvlow)*20d));
				
				//as temperature increases cooling increases
				//heating
				ReadingDetails srcdevice15 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[4], deviceIds[4],
						source.getLocation(), recordTime, vvlow.toString());
				
				Double tot = Double.parseDouble(srcdevice11.getValue()) +
				Double.parseDouble(srcdevice12.getValue()) +
				Double.parseDouble(srcdevice13.getValue()) +
				Double.parseDouble(srcdevice14.getValue()) +
				Double.parseDouble(srcdevice15.getValue()) +
				Double.parseDouble(srcdevice16.getValue());
				
				//total ec
				ReadingDetails srcdevice18 = new ReadingDetails(
				source.getResearchId(), source.getGroupId(),
				source.getSrcId(), deviceTypes[7], deviceIds[7],
				source.getLocation(), recordTime, df.format(tot));
				
				l.add(srcdevice11);
				l.add(srcdevice12);
				l.add(srcdevice13);
				l.add(srcdevice14);
				l.add(srcdevice15);
				l.add(srcdevice16);
				l.add(srcdevice17);
				l.add(srcdevice18);
				
			} else if (source.getSrcId().equals(DataSimulator.srcs[1].getSrcId())) {
				
				//Home: location London- coastal warm, low enter
				
				//lights
				ReadingDetails srcdevice11 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[0], deviceIds[0],
						source.getLocation(), recordTime, low.toString());

				//cooling
				ReadingDetails srcdevice12 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[1], deviceIds[1],
						source.getLocation(), recordTime, vlow.toString());

				//furnace
				ReadingDetails srcdevice13 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[2], deviceIds[2],
						source.getLocation(), recordTime, vlow.toString());

				//refrigerator
				ReadingDetails srcdevice14 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[3], deviceIds[3],
						source.getLocation(), recordTime, medium.toString());

				//entertainment
				ReadingDetails srcdevice16 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[5], deviceIds[5],
						source.getLocation(), recordTime, vhigh.toString());

				//temperature
				ReadingDetails srcdevice17 = null;
				if (isDay(now)) {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempLonDay);
				} else {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempLonNight);
				}

				//heating (increases as temp decreaes)
				ReadingDetails srcdevice15 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[4], deviceIds[4],
						source.getLocation(), recordTime, 
				df.format(600d - (Double.parseDouble(srcdevice17.getValue()) * (10d + Double.parseDouble(vvlow))))  );
				
				Double tot = Double.parseDouble(srcdevice11.getValue()) +
				Double.parseDouble(srcdevice12.getValue()) +
				Double.parseDouble(srcdevice13.getValue()) +
				Double.parseDouble(srcdevice14.getValue()) +
				Double.parseDouble(srcdevice15.getValue()) +
				Double.parseDouble(srcdevice16.getValue());
				 
				//total ec
				ReadingDetails srcdevice18 = new ReadingDetails(
				source.getResearchId(), source.getGroupId(),
				source.getSrcId(), deviceTypes[7], deviceIds[7],
				source.getLocation(), recordTime, df.format(tot));
				
				//door
				ReadingDetails srcdevice19 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[8], deviceIds[8],
						source.getLocation(), recordTime, freq.toString());
				
				l.add(srcdevice11);
				l.add(srcdevice12);
				l.add(srcdevice13);
				l.add(srcdevice14);
				l.add(srcdevice15);
				l.add(srcdevice16);
				l.add(srcdevice17);
				l.add(srcdevice18);
				l.add(srcdevice19);
			} else if (source.getSrcId().equals(DataSimulator.srcs[2].getSrcId())) {
				
				//Hospital: location 1 : bad service
				
				//lights
				ReadingDetails srcdevice11 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[0], deviceIds[0],
						source.getLocation(), recordTime, low.toString());

				//cooling
				ReadingDetails srcdevice12 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[1], deviceIds[1],
						source.getLocation(), recordTime, medium.toString());

				//entertainment
				ReadingDetails srcdevice16 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[5], deviceIds[5],
						source.getLocation(), recordTime, vvlow.toString());
				
				

				
				Double tot = Double.parseDouble(srcdevice11.getValue()) +
				Double.parseDouble(srcdevice12.getValue()) +
				Double.parseDouble(srcdevice16.getValue());
				 
				//total ec
				ReadingDetails srcdevice18 = new ReadingDetails(
				source.getResearchId(), source.getGroupId(),
				source.getSrcId(), deviceTypes[7], deviceIds[7],
				source.getLocation(), recordTime, df.format(tot));
				
				//heart-rate
				
				String nhr = "";
				if (abnormalhr[countRand] == 1) {
					nhr = heartRateHigh;
				} if (abnormalhr[countRand] == 0) {
					nhr = heartRateNormal;
				} if (abnormalhr[countRand] < 0) {
					nhr = heartRateLow;
				}
				
				ReadingDetails srcdevice110 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[9], deviceIds[9],
						source.getLocation(), recordTime, nhr);
				
				l.add(srcdevice11);
				l.add(srcdevice12);
				l.add(srcdevice16);
				l.add(srcdevice18);
				l.add(srcdevice110);
			} else if (source.getSrcId().equals(DataSimulator.srcs[3].getSrcId())) {
				
				//Hospital: location 1 : good service
				
				//lights
				ReadingDetails srcdevice11 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[0], deviceIds[0],
						source.getLocation(), recordTime, low.toString());

				//cooling
				ReadingDetails srcdevice12 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[1], deviceIds[1],
						source.getLocation(), recordTime, medium.toString());

				//entertainment
				ReadingDetails srcdevice16 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[5], deviceIds[5],
						source.getLocation(), recordTime, vvlow.toString());
				
				

				
				Double tot = Double.parseDouble(srcdevice11.getValue()) +
				Double.parseDouble(srcdevice12.getValue()) +
				Double.parseDouble(srcdevice16.getValue());
				 
				//total ec
				ReadingDetails srcdevice18 = new ReadingDetails(
				source.getResearchId(), source.getGroupId(),
				source.getSrcId(), deviceTypes[7], deviceIds[7],
				source.getLocation(), recordTime, df.format(tot));
				
				//heart-rate
				String nhr = null;
				if (normalhr[countRand] == 1) {
					nhr = heartRateHigh;
				} if (normalhr[countRand] == 0) {
					nhr = heartRateNormal;
				} if (normalhr[countRand] < 0) {
					nhr = heartRateLow;
				}
				
				ReadingDetails srcdevice110 = new ReadingDetails(
						source.getResearchId(), source.getGroupId(),
						source.getSrcId(), deviceTypes[9], deviceIds[9],
						source.getLocation(), recordTime, nhr);
				
				
				l.add(srcdevice11);
				l.add(srcdevice12);
				l.add(srcdevice16);
				l.add(srcdevice18);
				l.add(srcdevice110);
			} else if (source.getSrcId().equals(DataSimulator.srcs[4].getSrcId())) {
				
				//Home: location London- coastal warm, low enter
				//temperature
				ReadingDetails srcdevice17 = null;
				
				if (isDay(now)) {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempLonDay);
				} else {
					srcdevice17 = new ReadingDetails(source.getResearchId(),
							source.getGroupId(), source.getSrcId(),
							deviceTypes[6], deviceIds[6], source.getLocation(),
							recordTime, tempLonNight);
				}
				
				
				ReadingDetails srcdevice171 = new ReadingDetails(source.getResearchId(),
						source.getGroupId(), source.getSrcId(),
						deviceTypes[6], deviceIds[10], source.getLocation(),
						recordTime, Double.toString(Double.parseDouble(tempLonNight) -2) );
				
				ReadingDetails srcdevice172 = new ReadingDetails(source.getResearchId(),
						source.getGroupId(), source.getSrcId(),
						deviceTypes[6], deviceIds[11], source.getLocation(),
						recordTime, Double.toString(Double.parseDouble(tempLonDay) + 8));
				
				ReadingDetails srcdevice173 = new ReadingDetails(source.getResearchId(),
						source.getGroupId(), source.getSrcId(),
						deviceTypes[6], deviceIds[12], source.getLocation(),
						recordTime, tempLonNight);
				
				l.add(srcdevice17);
				l.add(srcdevice171);
				l.add(srcdevice172);
				l.add(srcdevice173);
				
			}
			ReadingRequest req = new ReadingRequest(l);
//			System.out.println(req);
			new MSRResource().storeInHbase(req);
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
//			System.out.println("Countdown!!!!!!!!!!!!!!!!!");
			countDownLatch.countDown();
		}

	}

	public static String getRandomValue(final Random random,
			final int lowerBound, final int upperBound, final int decimalPlaces) {

		final double dbl = ((random == null ? new Random() : random)
				.nextDouble() //
				* (upperBound - lowerBound))
				+ lowerBound;
		return String.format("%." + decimalPlaces + "f", dbl);

	}

	private static boolean isDay(Date d) {
		GregorianCalendar gc1 = new GregorianCalendar();
		gc1.setTime(d);
		int h = gc1.get(Calendar.HOUR_OF_DAY);
		if (h >= 8 && h < 23)
			return true;
		return false;
	}
}
